/*
 * =====================================================================================
 * Copyright (C) 2024 Ingenic Semiconductor Co.,Ltd
 * All Rights Reserved
 *
 * Filename     : i2c.c
 * Author       : Keven <keven.ywhan@ingenic.com>
 * Created      : 2024/06/04 16:56
 * Description  :
 *
 * =====================================================================================
 */

#include <string.h>
#include "common/reg_i2c.h"
#include "common/pdma.h"
#include "printk.h"
#include "tick.h"
#include "interrupt.h"
#include "duplex_list.h"
#include "kmalloc.h"
#include "completion.h"
#include "mutex.h"
#include "spinlock.h"
#include "msleep.h"
#include "gpio.h"
#include "i2c.h"

#define I2C_DEVICE_NUM_MAX    (3)
#define I2C_CHAIN_NUM_MAX     (32)

struct i2c_device {
	int32_t id;
	uint32_t state;
	uint32_t base;
	int32_t irq;
	int32_t refcnt;

	uint8_t *w_buf;
	uint8_t *r_buf;
	int32_t len;
	int32_t rd_len;

	uint32_t dma_tx_chn;
	uint32_t dma_rx_chn;
	uint32_t dma_rq_tx;
	uint32_t dma_rq_rx;

	uint32_t rw_buf_addr;
	uint32_t rw_buf_size;

	void (*callback)(void *cb_data);
	void *cb_data;

	struct completion done;
	struct completion dma_done;
	struct mutex mutex;
	spinlock_t slock;

	struct list_head buf_list;
	struct list_head queues_list;
	uint32_t block_flag;

};

struct i2c_dma_chain {
	struct list_head entry;
	uint16_t index;
	uint32_t work_mode;
	struct i2c_msg msg;
};

struct buf_c8_v8 {
	uint8_t cmd;
	uint8_t val;
};

struct buf_c16_v8 {
	uint16_t cmd;
	uint8_t val;
};

struct buf_c8_v16 {
	uint8_t cmd;
	uint16_t val;
};

struct buf_c16_v16 {
	uint16_t cmd;
	uint16_t val;
};

struct i2c_device i2c_devices_g[I2C_DEVICE_NUM_MAX] = {0};

static inline uint32_t i2c_readl(struct i2c_device *i2c,
		unsigned short offset)
{
	return readl(i2c->base + offset);
}

static inline void i2c_writel(struct i2c_device *i2c, unsigned short offset,
		unsigned short value)
{
	writel(value, i2c->base + offset);
}

static void show_txabrt(struct i2c_device *i2c, uint32_t value)
{
	int32_t i = 0;

	for (i = 0; i < 16; i++) {
		if (value & (0x1 << i)) {
			printk("--I2C TXABRT[%d] error\n", i);
		}
	}
	i2c_readl(i2c, I2C_CTXABRT);
}

static int32_t i2c_enable(struct i2c_device *i2c)
{
	int32_t delay = 1000;

	i2c_writel(i2c, I2C_ENABLE, 1);
	while(delay-- && !(i2c_readl(i2c, I2C_ENBST) & 0x1))
		udelay(50);

	if(!delay) {
		printk("i2c(%d) disable timeout\n", i2c->id);
		return -1;
	}

	return 0;
}

static int32_t i2c_disable(struct i2c_device *i2c)
{
	int32_t delay = 1000;

	i2c_writel(i2c, I2C_ENABLE, 0);
	while(delay-- && !(i2c_readl(i2c, I2C_ENBST) & 0x1))
		udelay(50);

	if(!delay) {
		printk("i2c(%d) disable timeout\n", i2c->id);
		return -1;
	}

	return 0;
}

static int32_t i2c_wait_idle(struct i2c_device *i2c)
{
	int32_t delay = 2000;

	while(delay-- && !(i2c_readl(i2c, I2C_ST) & 0x1<<5))
		udelay(1000);

	if(!delay) {
		printk("i2c(%d) wait idle timeout\n", i2c->id);
		return -1;
	}

	return 0;
}

static void i2c_set_speed(struct i2c_device *i2c)
{
	int32_t cnt_high = 0;	/* HIGH period count of the SCL clock */
	int32_t cnt_low = 0;	/* LOW period count of the SCL clock */
	int32_t setup_time = 0;
	int32_t hold_time = 0;
	int32_t rate;
	uint32_t bus_rate = 100000000;

	rate = 400000;

	if(i2c_disable(i2c))
		printk("i2c not disable\n");

	if(rate < 100000) {
		i2c_writel(i2c, I2C_CTRL, 0x1<<1);
	} else {
		i2c_writel(i2c, I2C_CTRL, 0x1<<2);
	}

	/*         high
	 *         ____     ____      ____      ____
	 *  clk __|  | |___|    |____|    |____|    |___
	 *           | | |
	 *           | | |
	 *           |_|_|     _________      ____
	 * data    __/ | |\___/         \____/    \____
	 *    setup->| |<|
	 *           ->| |<-hold
	 */

	setup_time = (bus_rate / (rate * 4));
	if (setup_time > 1)
		setup_time -= 1;
	hold_time = (bus_rate / (rate * 4));

	/*         high
	 *         ____     ____
	 *  clk __|    |___|    |____
	 *              low
	 *        |<--period--->|
	 *
	 */
	cnt_high = bus_rate/ (rate * 2);
	cnt_low = bus_rate / (rate * 2);

	if (setup_time > 255)
		setup_time = 255;
	if (setup_time <= 0)
		setup_time = 1;

	if (hold_time > 0xFFFF)
		hold_time = 0xFFFF;

	if (rate <= 100000) {
		i2c_writel(i2c, I2C_SHCNT, I2CSHCNT_ADJUST(cnt_high));
		i2c_writel(i2c, I2C_SLCNT, I2CSLCNT_ADJUST(cnt_low));
	} else {
		i2c_writel(i2c, I2C_FHCNT, I2CFHCNT_ADJUST(cnt_high));
		i2c_writel(i2c, I2C_FLCNT, I2CFLCNT_ADJUST(cnt_low));
	}

	i2c_writel(i2c, I2C_SDASU, setup_time & 0xff);
	i2c_writel(i2c, I2C_SDAHD, hold_time);

}

static void i2c_mask_irq(struct i2c_device *i2c)
{
	i2c_writel(i2c, I2C_INTM, 0);
}

static void i2c_write_tx_fifo(struct i2c_device *i2c, int32_t first)
{
	uint16_t value = 0;

	while((i2c->len > 0) && (i2c_readl(i2c, I2C_ST) & I2C_STA_TFNF)) {
		value = *i2c->w_buf++;
		if(first) {
			value |= I2C_DC_REST;
			first = 0;
		}
		if (i2c->len == 1) {
			value |= I2C_DC_STP;
		}
		i2c_writel(i2c, I2C_DC, value);
		i2c->len--;
	}

	if(i2c->len == 0)
		i2c_writel(i2c, I2C_TXTL, 0);
}

static int32_t i2c_set_device_addr(struct i2c_device *i2c, uint16_t dev_addr, uint8_t is_10bit)
{
	int32_t ret = 0;
	uint32_t value = 0;

	i2c_writel(i2c, I2C_DMACR, 0);

	value = i2c_readl(i2c, I2C_TAR);
	if(is_10bit)
		value |= (0x1<<12);
	else
		value &= ~(0x1<<12);
	value &= ~(0x3ff);
	value |= dev_addr;
	i2c_writel(i2c, I2C_TAR, value);

	return ret;
}

static int32_t i2c_transmit_cmd(struct i2c_device *i2c, uint8_t *buf, uint16_t len)
{
	int32_t ret = 0;
	uint32_t value = 0;
	int32_t i;

	for(i = 0; i < len; i++) {
		value = *(uint8_t *)buf;
		if(i == len-1)
			value |= I2C_DC_REST;
		i2c_writel(i2c, I2C_DC, value);
	}

	return ret;
}


static void i2c_send_read_cmd(struct i2c_device *i2c, int32_t first)
{
	uint16_t value = 0;

	while((i2c->rd_len > 0) && (i2c_readl(i2c, I2C_ST) & I2C_STA_TFNF)) {
		value = I2C_DC_READ;
		if(first) {
			value |= I2C_DC_REST;
			first = 0;
		}
		if (i2c->rd_len == 1) {
			value |= I2C_DC_STP;
		}
		i2c_writel(i2c, I2C_DC, value);
		i2c->rd_len--;
	}

}

static void i2c_read_rx_fifo(struct i2c_device *i2c)
{
	uint16_t value = 0;

	while((i2c->len > 0) && (i2c_readl(i2c, I2C_ST) & I2C_STA_RFNE)) {
		value = i2c_readl(i2c, I2C_DC) & 0xff;
		*i2c->r_buf++ = value;
		i2c->len--;
	}

}

static int32_t dam_data_format_conver(void *src_buf, void *dst_buf, int32_t buf_len, uint32_t data_format)
{
	int32_t i = 0;
	int32_t j = 0;
	struct buf_c8_v8 *c8_v8 = (struct buf_c8_v8 *)src_buf;
	struct buf_c16_v8 *c16_v8 = (struct buf_c16_v8 *)src_buf;
	struct buf_c8_v16 *c8_v16 = (struct buf_c8_v16 *)src_buf;
	struct buf_c16_v16 *c16_v16 = (struct buf_c16_v16 *)src_buf;
	uint16_t *buffer = (uint16_t*)dst_buf;

	if(data_format == REG_8BIT_VALUE_8BIT) {
		for(i = 0, j = 0; i < buf_len; i++) {
			buffer[j++] = c8_v8[i].cmd;
			buffer[j++] = c8_v8[i].val | I2C_DC_STP;
		}
	} else if(data_format == REG_16BIT_VALUE_8BIT) {
		for(i = 0, j = 0; i < buf_len; i++) {
			buffer[j++] = c16_v8[i].cmd>>8;
			buffer[j++] = (c16_v8[i].cmd & 0xff);
			buffer[j++] = c16_v8[i].val | I2C_DC_STP;
		}
	} else if(data_format == REG_8BIT_VALUE_16BIT) {
		for(i = 0, j = 0; i < buf_len; i++) {
			buffer[j++] = c8_v16[i].cmd;
			buffer[j++] = c8_v16[i].val>>8;
			buffer[j++] = (c8_v16[i].val & 0xff) | I2C_DC_STP;
		}
	} else if(data_format == REG_16BIT_VALUE_16BIT) {
		for(i = 0, j = 0; i < buf_len; i++) {
			buffer[j++] = c16_v16[i].cmd>>8;
			buffer[j++] = (c16_v16[i].cmd & 0xff);
			buffer[j++] = c16_v16[i].val>>8;
			buffer[j++] = (c16_v16[i].val & 0xff) | I2C_DC_STP;
		}
	}

	return j;
}

static int32_t i2c_dma_transmit(struct i2c_device *i2c, void *buf, uint32_t count, uint32_t data_format);
static int32_t i2c_dma_receive(struct i2c_device *i2c, void *buf, uint32_t count, uint32_t data_format);

static void dma_write_done_callback(void *data)
{
	struct i2c_device *i2c = (struct i2c_device *)data;
	struct i2c_dma_chain *chain;
	struct i2c_msg *msg;

	i2c->state = I2C_STATE_READY;
	chain = list_first_entry_or_null(&i2c->queues_list, struct i2c_dma_chain, entry);
	if(!chain) {
		printk("error! i2c dma chain list is null\n");
		return;
	}
	list_del(&chain->entry);
	list_add_tail(&chain->entry, &i2c->buf_list);
	msg = &chain->msg;
	if(msg->callback) {
		msg->callback(msg->cb_data);
	}
	/* printk("%s %d\n",__func__,__LINE__); */

	if(list_empty(&i2c->queues_list)) {
		if(i2c->block_flag == 1) {
			i2c->block_flag = 0;
			complete_isr(&i2c->dma_done);
		}
	} else {
		chain = list_first_entry(&i2c->queues_list, struct i2c_dma_chain, entry);
		if(chain->msg.flags == I2C_DMA_MODE) {
			if(chain->msg.flags & I2C_ADDR_10BIT)
				i2c_set_device_addr(i2c, chain->msg.addr, 1);
			else
				i2c_set_device_addr(i2c, chain->msg.addr, 0);
			i2c_dma_transmit(i2c, chain->msg.buf, chain->msg.len, chain->msg.buf_data_format);
		} else {
			printk("no support dma read\n");
		}
	}
}

static void i2c_irq_handler(int32_t irq, void *data)
{
	struct i2c_device *i2c = (struct i2c_device *)data;
	uint32_t intst, intmsk;

	intst = i2c_readl(i2c, I2C_INTST);
	intmsk = i2c_readl(i2c, I2C_INTM);
	/* printk("%s %d, intst = 0x%08x, intmsk = 0x%08x\n",__func__,__LINE__,intst, intmsk); */

	/* TXABT 中断被触发 */
	if (intst & I2C_INTST_TXABT) {
		//清 TXABT 中断
		i2c_writel(i2c, I2C_INTM, 0);
	}

	if (intst & I2C_INTST_ISTP) {
		/* 清stop中断 */
		i2c_readl(i2c, I2C_CSTP);
	}

	if ((intst & I2C_INTST_RXOF) && (intmsk & I2C_INTM_MRXOF)) {
		i2c_readl(i2c, I2C_CRXOF);
		printk("%s %d, i2c tarnsfer error, rxfifo over full\n",__func__,__LINE__);
	}

	if ((intst & I2C_INTST_TXOF) && (intmsk & I2C_INTM_MTXOF)) {
		i2c_readl(i2c, I2C_CRXOF);
		printk("%s %d, i2c tarnsfer error, txfifo over full\n",__func__,__LINE__);
	}

	/* TX FIFO 空中断被触发 */
	if ((intst & I2C_INTST_TXEMP) && (intmsk & I2C_INTM_MTXEMP)) {
		if (i2c->len == 0) {
			goto I2C_IRQ_END;
		} else {
			i2c_write_tx_fifo(i2c, 0);
		}
	}

	/* RX FIFO 满中断被触发 */
	if ((intst & I2C_INTST_RXFL) && (intmsk & I2C_INTM_MRXFL)) {
		i2c_read_rx_fifo(i2c);
		if (i2c->len == 0) {
			goto I2C_IRQ_END;
		} else {
			if(i2c->len > I2C_FIFO_LEN)
				i2c_writel(i2c, I2C_RXTL, RX_LEVEL);
			else
				i2c_writel(i2c, I2C_RXTL, i2c->len-1);

			i2c_send_read_cmd(i2c, 0);
		}
	}

	/* 停止信号中断被触发 */
	if (intst & I2C_INTST_ISTP) {
		if (i2c->len == 0) {
			goto I2C_IRQ_END;
		}
	}

	printk("%s %d, intst = 0x%08x, intmsk = 0x%08x\n",__func__,__LINE__,intst, intmsk);

	return;

I2C_IRQ_END:
	i2c_writel(i2c, I2C_INTM, 0);
	complete_isr(&i2c->done);
	return;
}

static int32_t i2c_pio_transmit(struct i2c_device *i2c, void *buf, uint32_t data_format)
{
	int32_t ret = 0;
	int32_t timeout = 2000;
	uint32_t value;

	uint8_t cd_buf[4] = {0};
	uint8_t cd_buf_len = 0;
	struct buf_c8_v8 *c8_v8 = (struct buf_c8_v8 *)buf;
	struct buf_c8_v16 *c8_v16 = (struct buf_c8_v16 *)buf;
	struct buf_c16_v8 *c16_v8 = (struct buf_c16_v8 *)buf;
	struct buf_c16_v16 *c16_v16 = (struct buf_c16_v16 *)buf;

	if(data_format == REG_8BIT_VALUE_8BIT) {
		cd_buf[0] = c8_v8->cmd;
		cd_buf[1] = c8_v8->val;
		cd_buf_len = 2;
	} else if(data_format == REG_8BIT_VALUE_16BIT) {
		cd_buf[0] = c8_v16->cmd;
		cd_buf[1] = c8_v16->val>>8;
		cd_buf[2] = c8_v16->val & 0xff;
		cd_buf_len = 3;
	} else if(data_format == REG_16BIT_VALUE_8BIT) {
		cd_buf[0] = c16_v8->cmd>>8;
		cd_buf[1] = c16_v8->cmd & 0xff;
		cd_buf[2] = c16_v8->val;
		cd_buf_len = 3;
	} else if(data_format == REG_16BIT_VALUE_16BIT) {
		cd_buf[0] = c16_v16->cmd>>8;
		cd_buf[1] = c16_v16->cmd & 0xff;
		cd_buf[2] = c16_v16->val>>8;
		cd_buf[3] = c16_v16->val & 0xff;
		cd_buf_len = 4;
	}

	i2c->w_buf = cd_buf;
	i2c->len = cd_buf_len;

	/* clear stp txof txabrt bit*/
	i2c_readl(i2c, I2C_CSTP);
	i2c_readl(i2c, I2C_CTXOF);
	i2c_readl(i2c, I2C_CTXABRT);

	i2c_writel(i2c, I2C_TXTL, TX_LEVEL);

	i2c_write_tx_fifo(i2c, 0);

	/* 开中断 */
	value = i2c_readl(i2c, I2C_INTM);
	value |= I2C_INTM_MTXEMP | I2C_INTM_MTXABT | I2C_INTM_MTXOF;
	if(i2c->len == 0)
		value |= I2C_INTM_MISTP;
	i2c_writel(i2c, I2C_INTM, value);

	ret = wait_for_completion_timeout(&i2c->done, timeout);
	if(!ret) {
		printk("i2c transfer timeout\n");
		ret = -1;
	}

	value = i2c_readl(i2c, I2C_ABTSRC);
	if(value) {
		printk("i2c transfer abrt\n");
		show_txabrt(i2c, value);
		ret = -1;
	}

	return ret;
}

static int32_t i2c_pio_receive(struct i2c_device *i2c, void *buf, uint32_t data_format)
{
	int32_t ret = 0;
	int32_t timeout = 2000;
	uint32_t value;

	uint8_t cmd_buf[2] = {0};
	uint8_t data_buf[2] = {0};
	uint16_t cmd_len = 0;
	uint16_t data_len = 0;
	struct buf_c8_v8 *c8_v8 = (struct buf_c8_v8 *)buf;
	struct buf_c8_v16 *c8_v16 = (struct buf_c8_v16 *)buf;
	struct buf_c16_v8 *c16_v8 = (struct buf_c16_v8 *)buf;
	struct buf_c16_v16 *c16_v16 = (struct buf_c16_v16 *)buf;

	if(data_format == REG_8BIT_VALUE_8BIT) {
		cmd_buf[0] = c8_v8->cmd;
		cmd_len = 1;
		data_len = 1;
	} else if(data_format == REG_8BIT_VALUE_16BIT) {
		cmd_buf[0] = c8_v16->cmd;
		cmd_len = 1;
		data_len = 2;
	} else if(data_format == REG_16BIT_VALUE_8BIT) {
		cmd_buf[0] = c16_v8->cmd>>8;
		cmd_buf[1] = c16_v8->cmd & 0xff;
		cmd_len = 2;
		data_len = 1;
	} else if(data_format == REG_16BIT_VALUE_16BIT) {
		cmd_buf[0] = c16_v16->cmd>>8;
		cmd_buf[1] = c16_v16->cmd & 0xff;
		cmd_len = 2;
		data_len = 2;
	}

	i2c_transmit_cmd(i2c, (uint8_t *)cmd_buf, cmd_len);

	i2c->r_buf = data_buf;
	i2c->len = data_len;
	i2c->rd_len = data_len;

	/* clear stp txof txabrt bit*/
	i2c_readl(i2c, I2C_CSTP);
	i2c_readl(i2c, I2C_CTXOF);
	i2c_readl(i2c, I2C_CTXABRT);

	if(i2c->len > I2C_FIFO_LEN)
		i2c_writel(i2c, I2C_RXTL, RX_LEVEL);
	else
		i2c_writel(i2c, I2C_RXTL, i2c->len-1);

	i2c_send_read_cmd(i2c, 0);

	/* 开中断 */
	value = i2c_readl(i2c, I2C_INTM);
	/* value |= I2C_INTM_MRXFL | I2C_INTM_MTXABT; */
	value |= I2C_INTM_MRXFL;
	if(i2c->rd_len == 0)
		value |= I2C_INTM_MISTP;
	i2c_writel(i2c, I2C_INTM, value);

	ret = wait_for_completion_timeout(&i2c->done, timeout);
	if(!ret) {
		printk("i2c receive timeout\n");
		ret = -1;
	}

	if(data_format == REG_8BIT_VALUE_8BIT) {
		c8_v8->val = data_buf[0];
	} else if(data_format == REG_8BIT_VALUE_16BIT) {
		c8_v16->val = data_buf[0]<<8 | data_buf[1];
	} else if(data_format == REG_16BIT_VALUE_8BIT) {
		c16_v8->val = data_buf[0];
	} else if(data_format == REG_16BIT_VALUE_16BIT) {
		c16_v16->val = data_buf[0]<<8 | data_buf[1];
	}

	return ret;
}

static int32_t i2c_dma_transmit(struct i2c_device *i2c, void *buf, uint32_t count, uint32_t data_format)
{
	int32_t ret = 0;
	uint32_t buf_addr = i2c->rw_buf_addr;
	uint32_t dma_tran_count = 0;
	struct dma_channel_cfg config;

	if(count * 4 > i2c->rw_buf_size) {
		printk("%s %d, Error! msg len(%d) > rw_buf_len(%d)\n",
				__func__,__LINE__, count * 4, i2c->rw_buf_size);
		return -1;
	}

	dma_tran_count = dam_data_format_conver(buf, (void *)buf_addr, count, data_format);
	if(dma_tran_count < 1) {
		printk("%s %d, Error! buf_len is invalidate\n", __func__, __LINE__);
		return -1;
	}

	i2c_writel(i2c, I2C_INTM, 0);
	i2c_writel(i2c, I2C_DMACR, 0x1<<1);
	i2c_writel(i2c, I2C_DMATDLR, TX_LEVEL);

	config.src_addr = buf_addr;
	config.dst_addr = i2c->base + I2C_DC;
	config.src_addr_inc_en = 1;
	config.dst_addr_inc_en = 0;
	config.src_port_width = DMA_PORT_16BIT;
	config.dst_port_width = DMA_PORT_16BIT;
	config.tran_data_count = dma_tran_count;
	config.tran_data_uint = BYTE2; //16bit
	config.dma_requset_type = i2c->dma_rq_tx;

	config.callback = dma_write_done_callback;
	config.cb_data = i2c;

	dma_config_channel(i2c->dma_tx_chn, &config);
	dma_start_channel(i2c->dma_tx_chn);


	return ret;
}

int32_t i2c_init(struct i2c_config *config)
{
	int32_t ret = 0;
	uint32_t value = 0;
	struct i2c_device *i2c = NULL;
	struct i2c_dma_chain *chain;
	void *chain_buf;
	int32_t i;

	if(config == NULL) {
		printk("%s %d, error! i2c config is null\n",__func__, __LINE__);
		return -1;
	}
	if(config->adapter >= I2C_DEVICE_NUM_MAX) {
		printk("%s %d, error! i2c device number %d > %d(max)\n",
				__func__, __LINE__, config->adapter, I2C_DEVICE_NUM_MAX);
		return -1;
	}

	i2c = &i2c_devices_g[config->adapter];
	if(i2c->refcnt) {
		i2c->refcnt++;
		return 0;
	}
	i2c->refcnt++;

	i2c->id = config->adapter;
	if(i2c->id == 0) {
		i2c->base = I2C0_BASE;
		i2c->irq = IRQ_INTC1_I2C0;
		i2c->dma_rq_tx = DMA_RQ_I2C0_TX;
		i2c->dma_rq_rx = DMA_RQ_I2C0_RX;
	} else if(i2c->id == 1) {
		i2c->base = I2C1_BASE;
		i2c->irq = IRQ_INTC1_I2C1;
		i2c->dma_rq_tx = DMA_RQ_I2C1_TX;
		i2c->dma_rq_rx = DMA_RQ_I2C1_RX;
	} else if(i2c->id == 2) {
		i2c->base = I2C2_BASE;
		i2c->irq = IRQ_INTC1_I2C2;
		i2c->dma_rq_tx = DMA_RQ_I2C2_TX;
		i2c->dma_rq_rx = DMA_RQ_I2C2_RX;
	}

	i2c->dma_tx_chn = dma_request_channel();
	i2c->dma_rx_chn = dma_request_channel();
	if(config->dma_buf_addr && config->dma_buf_size) {
		i2c->rw_buf_size = config->dma_buf_size;
		i2c->rw_buf_addr = config->dma_buf_addr;
	} else {
		printk("error! dma_buf_addr = 0x%x, dma_buf_size = %d\n",
				config->dma_buf_addr, config->dma_buf_size);
		return -1;
	}

	mutex_init(&i2c->mutex);
	spin_lock_init(&i2c->slock);
	init_completion(&i2c->done);
	init_completion(&i2c->dma_done);

	INIT_LIST_HEAD(&i2c->buf_list);
	INIT_LIST_HEAD(&i2c->queues_list);

	chain_buf = kmalloc(sizeof(struct i2c_dma_chain) * I2C_CHAIN_NUM_MAX);
	if(!chain_buf) {
		printk("%s %d, chain_buf alloc failed\n",__func__,__LINE__);
	}
	for(i = 0; i < I2C_CHAIN_NUM_MAX; i++) {
		chain = (struct i2c_dma_chain *)chain_buf + i;
		chain->index = i;
		chain->work_mode = 0;
		list_add_tail(&chain->entry, &i2c->buf_list);
	}

	/* Disable the selected I2C peripheral */
	i2c_disable(i2c);

	i2c_set_speed(i2c);

	value = i2c_readl(i2c, I2C_CTRL);
	value |= 0x1<<6; //slave disable
	value |= 0x1<<5; //restart enable
	value &= ~(0x1<<3); //7bit addr
	value |= 0x1; //master enable
	i2c_writel(i2c, I2C_CTRL, value);
	/* set filter */
	i2c_writel(i2c, I2C_FSPKLEN, 0xf);
	/* 关闭mask中断 */
	i2c_mask_irq(i2c);

	request_irq(i2c->irq, i2c_irq_handler, i2c);

	i2c_enable(i2c);
	set_irq_priority(i2c->irq, IRQ_PRIORITY_MIDDLE);
	enable_irq(i2c->irq);
	i2c->state = I2C_STATE_READY;

	/* 初始化DMA接口 */
	dma_init();

	return ret;
}

int32_t i2c_write(struct i2c_msg *msg)
{
	int32_t ret = 0;
	struct i2c_device *i2c = NULL;
	struct i2c_dma_chain *chain;
	int32_t timeout = 2000;
	uint8_t *buf_p8 = NULL;
	uint8_t offset = 0;
	int32_t i;

	if(!msg){
		printk("%s %d, i2c write msg is null\n",__func__,__LINE__);
		return -1;
	}
	if(msg->adapter >= I2C_DEVICE_NUM_MAX) {
		printk("%s %d, error! i2c device number %d > %d(max)\n",
				__func__, __LINE__, msg->adapter, I2C_DEVICE_NUM_MAX);
		return -1;
	}

	i2c = &i2c_devices_g[msg->adapter];

	if(msg->flags & I2C_PIO_MODE) {
		mutex_lock(&i2c->mutex);
		spin_lock_irq(&i2c->slock);
		if(i2c->state == I2C_STATE_BUSY_DMA_TX || i2c->state == I2C_STATE_BUSY_DMA_RX) {
			i2c->block_flag = 1;
			spin_unlock_irq(&i2c->slock);
			ret = wait_for_completion_timeout(&i2c->dma_done, timeout);
			if(!ret) {
				mutex_unlock(&i2c->mutex);
				printk("i2c wait write timeout\n");
				return -1;
			}

			spin_lock_irq(&i2c->slock);
			i2c->state = I2C_STATE_BUSY_TX;
			spin_unlock_irq(&i2c->slock);
		} else {
			i2c->state = I2C_STATE_BUSY_TX;
			spin_unlock_irq(&i2c->slock);
		}

		if(msg->flags & I2C_ADDR_10BIT)
			i2c_set_device_addr(i2c, msg->addr, 1);
		else
			i2c_set_device_addr(i2c, msg->addr, 0);

		if(msg->buf_data_format == REG_8BIT_VALUE_8BIT) {
			offset = 2;
		} else if(msg->buf_data_format == REG_8BIT_VALUE_16BIT) {
			offset = 3;
		} else if(msg->buf_data_format == REG_16BIT_VALUE_8BIT) {
			offset = 3;
		} else if(msg->buf_data_format == REG_16BIT_VALUE_16BIT) {
			offset = 4;
		}

		buf_p8 = msg->buf;
		for(i = 0; i < msg->len; i++) {
			buf_p8 = buf_p8 + offset * i;
			i2c_pio_transmit(i2c, (void *)buf_p8, msg->buf_data_format);
		}

		spin_lock_irq(&i2c->slock);
		i2c->state = I2C_STATE_READY;
		spin_unlock_irq(&i2c->slock);

		mutex_unlock(&i2c->mutex);
	} else if(msg->flags & I2C_DMA_MODE) {
		spin_lock_irq(&i2c->slock);
		chain = list_first_entry_or_null(&i2c->buf_list, struct i2c_dma_chain, entry);
		if(!chain) {
			spin_unlock_irq(&i2c->slock);
			printk("error! i2c dma write chain list is null\n");
			return -1;
		}
		list_del(&chain->entry);
		list_add_tail(&chain->entry, &i2c->queues_list);
		spin_unlock_irq(&i2c->slock);
		memcpy(&chain->msg, msg, sizeof(struct i2c_msg));

		spin_lock_irq(&i2c->slock);
		if(i2c->state == I2C_STATE_READY) {
			i2c->state = I2C_STATE_BUSY_DMA_TX;
			if(chain->msg.flags & I2C_ADDR_10BIT)
				i2c_set_device_addr(i2c, chain->msg.addr, 1);
			else
				i2c_set_device_addr(i2c, chain->msg.addr, 0);
			i2c_dma_transmit(i2c, chain->msg.buf, chain->msg.len, chain->msg.buf_data_format);
		}
		spin_unlock_irq(&i2c->slock);
	}

	return ret;
}

int32_t i2c_read(struct i2c_msg *msg)
{
	int32_t ret = 0;
	struct i2c_device *i2c = NULL;
	int32_t timeout = 2000;
	uint8_t *buf_p8 = NULL;
	uint8_t offset = 0;
	int32_t i;

	if(!msg) {
		printk("%s %d, i2c read msg is null \n",__func__,__LINE__);
		return -1;
	}

	if(msg->adapter >= I2C_DEVICE_NUM_MAX) {
		printk("%s %d, error! i2c device number %d > %d(max)\n",
				__func__, __LINE__, msg->adapter, I2C_DEVICE_NUM_MAX);
		return -1;
	}

	i2c = &i2c_devices_g[msg->adapter];

	if(msg->flags & I2C_PIO_MODE) {
		mutex_lock(&i2c->mutex);
		spin_lock_irq(&i2c->slock);
		if(i2c->state == I2C_STATE_BUSY_DMA_TX || i2c->state == I2C_STATE_BUSY_DMA_RX) {
			i2c->block_flag = 1;
			spin_unlock_irq(&i2c->slock);
			ret = wait_for_completion_timeout(&i2c->dma_done, timeout);
			if(!ret) {
				mutex_unlock(&i2c->mutex);
				printk("i2c wait read timeout\n");
				return -1;
			}
			spin_lock_irq(&i2c->slock);
			i2c->state = I2C_STATE_BUSY_RX;
			spin_unlock_irq(&i2c->slock);
		} else  {
			i2c->state = I2C_STATE_BUSY_RX;
			spin_unlock_irq(&i2c->slock);
		}

		if(msg->flags & I2C_ADDR_10BIT)
			i2c_set_device_addr(i2c, msg->addr, 1);
		else
			i2c_set_device_addr(i2c, msg->addr, 0);

		if(msg->buf_data_format == REG_8BIT_VALUE_8BIT) {
			offset = 2;
		} else if(msg->buf_data_format == REG_8BIT_VALUE_16BIT) {
			offset = 3;
		} else if(msg->buf_data_format == REG_16BIT_VALUE_8BIT) {
			offset = 3;
		} else if(msg->buf_data_format == REG_16BIT_VALUE_16BIT) {
			offset = 4;
		}

		buf_p8 = msg->buf;

		for(i = 0; i < msg->len; i++) {
			buf_p8 = buf_p8 + offset * i;
			i2c_pio_receive(i2c, (void *)buf_p8, msg->buf_data_format);
		}

		spin_lock_irq(&i2c->slock);
		i2c->state = I2C_STATE_READY;
		spin_unlock_irq(&i2c->slock);

		mutex_unlock(&i2c->mutex);
	} else if(msg->flags & I2C_DMA_MODE) {
		printk("no support dma read\n");
	}

	return ret;
}
